﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Windows.Browser;

using System.Threading;
using System.IO;

using Polenter.Serialization;
using Polenter.Serialization.Core;
using Polenter.Serialization.Serializing;
using Polenter.Serialization.Deserializing;

using MIRIA.Animations;
using MIRIA.Interaction;
using MIRIA.Interaction.MultiTouch;
using MIRIA.Interaction.NiteKinect;
using MIRIA.Interaction.WiiRemote;

using MIG.Client;
using MIG.Client.Devices.NiteKinect;

namespace MIRIADemo
{

    public partial class MainPage : UserControl
    {

        public static readonly DependencyProperty IsSpinningProperty = DependencyProperty.RegisterAttached("Hookable", typeof(bool), typeof(MainPage),
                                                                        new PropertyMetadata(false, null));

        public static void SetHookable(DependencyObject obj, bool hookable)
        {
            obj.SetValue(IsSpinningProperty, hookable);
        }
        public static bool GetHookable(DependencyObject obj)
        {
            return (bool)obj.GetValue(IsSpinningProperty);
        }



        private MIGClient _migclient;

        private TouchListener _touchlistener;
        private KinectListener _kinectlistener;
        private WiiRemoteListener _wiiremotelistener;
        
        public TransformHelper _transformhelper;



        public MainPage()
        {
            InitializeComponent();
            //
            _initialize();
            _initmiria();
        }


        private void _initmiria()
        {
            //
            // Multitouch TUIO / Standard Win 7 / Silverlight3 Multitouch / Mouse mapped as a single touch
            //
            _touchlistener = new TouchListener(LayoutRoot);
            //
            // Micrososft Kinect / PrimeSense Sensor - based on OpenNI NITE middleware
            //
            _kinectlistener = new KinectListener(LayoutRoot);
            _kinectlistener.HandElementEnter += new KinectListener.HandElementEnterEventHandler(_kinectlistener_HandElementEnter);
            _kinectlistener.HandElementExit += new KinectListener.HandElementExitEventHandler(_kinectlistener_HandElementExit);
            Kinect.SetKinectListener(_kinectlistener.MIGListener as MIG.Client.Devices.NiteKinect.Kinect);
            Kinect.Kinect.SkeltonUpdate += new MIG.Client.Devices.NiteKinect.Kinect.SkeltonUpdateHandler(Kinect_SkeltonUpdate);
            //
            // Nintendo Wii Remote - based on MonoWiiUse included in monoMIG project
            //
            _wiiremotelistener = new WiiRemoteListener(LayoutRoot);
            //WiiRemote.SetWiiRemoteListener(_wiiremotelistener.MIGListener as MIG.Client.Devices.Wii.Remote);
            //
            _migclient = new MIGClient();
            _migclient.AddListener("MT0", _touchlistener.MIGListener);
            _migclient.AddListener("KN0", _kinectlistener.MIGListener);
            _migclient.AddListener("WI0", _wiiremotelistener.MIGListener);
            _migclient.Connect();
        }

        void _kinectlistener_HandElementExit(object sender, HandElementEventArgs args)
        {
            //_animate_fadeall(1.0, 0.2, 0.0);
        }

        void _kinectlistener_HandElementEnter(object sender, HandElementEventArgs args)
        {
            //_animate_fadeallbut(args.Element, 0.9, 0.2, 0.0);
        }


        private List<Dictionary<SkeltonJoint, Point3d>> _skeltanimdata = null;
        private Dictionary<SkeltonJoint, Point3d> _currentskelton = new Dictionary<SkeltonJoint,Point3d>();
        void Kinect_SkeltonUpdate(object sender, KinectSkeltonUpdateEventArgs args)
        {
            Dictionary<SkeltonJoint, Point3d> kinectdatacopy = new Dictionary<SkeltonJoint, Point3d>();
            foreach (KeyValuePair<SkeltonJoint, Point3d> kv in args.Skelton)
            {
                kinectdatacopy.Add(kv.Key, kv.Value);
            }
            _currentskelton = kinectdatacopy;
        }

        private void _initialize()
        {
            _transformhelper = new TransformHelper(MainPanel);
            this.KeyUp += new KeyEventHandler(MainPage_KeyUp);
            //
            //Animator.AnimateProperty(MainPanel, "Scale", 1.0, 1.8, 0.5, 6.0, null);
            //Animator.AnimateProperty(MainPanel, "Y", 0.0, -118, 0.5, 6.0, null);
            //
            //Animator.AnimateProperty(MainPanel, "Scale", 1.8, 1.0, 32.0, 9.0, null);
            //Animator.AnimateProperty(MainPanel, "Y", -118, 0.0, 32.0, 9.0, null);
        }

        private void UserControl_Loaded(object sender, RoutedEventArgs e)
        {
            _transformhelper_ScaleToFullHeight();
            KinectPlay_Tapped(null, null);
            Animator.PlayScript(() =>
            {
                double starttime = 5.0;

                ScrollText.Dispatcher.BeginInvoke(() =>
                    {

                        foreach (UIElement el in ScrollText.Children)
                        {
                            el.Visibility = Visibility.Collapsed;
                        }
                        double ts = 0;
                        foreach (UIElement el in ScrollText.Children)
                        {
                            Animator.FxSuperimpose(el as FrameworkElement, starttime + ts);
                            ts += 3.25;
                        }

                    });

                return false;
            });
            _animate_fadeall(0.25, 0.5, 4);
            Animator.PlayScript(() =>
            {
                Thread.Sleep(38000);
                KinectRecord.Dispatcher.BeginInvoke(() =>
                    {
                        _animate_fadeall(1.00, 0.5, 0);
                        KinectRecord.HomeLocation = new Point(580, 370);
                        KinectRecord.SetValue(Canvas.ZIndexProperty, 100);
                    });
                Thread.Sleep(150);
                KinectPlay.Dispatcher.BeginInvoke(() =>
                {
                    KinectPlay.HomeLocation = new Point(540, 370);
                    KinectPlay.SetValue(Canvas.ZIndexProperty, 100);
                });
                Thread.Sleep(5000);
                MainPanel.Dispatcher.BeginInvoke(() =>
                {
                    HalButton.Animate();
                });
                return false;
            });
        }

        private void _transformhelper_ScaleToFullHeight()
        {
            for (int x = 0; x < ColumnTopRight.Children.Count; x++)
            {
                FrameworkElement el = (FrameworkElement)ColumnTopRight.Children[x];
                el.Visibility = System.Windows.Visibility.Collapsed;
            }
            _animate_pageopen(0.4, 2.0);
        }

        public static class ControlFinder
        {
            public static T FindParent<T>(UIElement control) where T : UIElement
            {
                UIElement p = VisualTreeHelper.GetParent(control) as UIElement;
                if (p != null)
                {
                    if (p is T)
                        return p as T;
                    else
                        return ControlFinder.FindParent<T>(p);
                }
                return null;
            }
        }


        private void Border_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            _animate_pageclose(0.4, 0.0);
            _animate_pageopen(0.4, 5.0);
        }

        private void MainPage_KeyUp(object sender, KeyEventArgs e)
        {
            if (e.Key == Key.D1)
            {
                _animate_pageclose(0.4, 0.0);
                _animate_pageopenfar(0.4, 1.1);
            }
            else
            {
                _animate_pageclose(0.4, 0.0);
                _animate_pageopen(0.4, 3.0);
            }
        }
        
        private void _animate_pageopenfar(double animationduration, double starttime)
        {
            Animator.FxComposePanelFar(ColumnTopRight, animationduration, starttime, null);
        }
        
        private void _animate_pageopen(double animationduration, double starttime)
        {
            Animator.FxComposePanelClose(ColumnTopRight, animationduration, starttime, null);
        }
        
        private void _animate_pageclose(double animationduration, double starttime)
        {
            Animator.FxDecomposePanelClose(ColumnTopRight, animationduration, starttime, null);
        }

        private void _animate_fadeall(double tovalue, double animationduration, double starttime)
        {
            List<FrameworkElement> exel = new List<FrameworkElement>() { KinectDemoButton };
            Animator.FxFadePanelFar(ColumnTopRight, tovalue, animationduration, starttime, exel);
        }


        

        private bool _playmode = false;
        private bool miriaanimstarted = false;
        private bool miganimstarted = false;
        private void KinectPlay_Tapped(object sender, FingerTouchEventArgs e)
        {
            _playmode = !_playmode;
            if (!_playmode) return;
            //
            SharpSerializer serializer = new SharpSerializer();
            //
            //MemoryStream ms = new MemoryStream();
            //serializer.Serialize(_skeltanimdata, ms);
            /* 
            try 
            {
                byte[] fileBytes = ms.GetBuffer(); //your bytes here 
                SaveFileDialog dialog=new SaveFileDialog();

                //Show the dialog              
                bool? dialogResult = dialog.ShowDialog();  

                if (dialogResult!=true) return;

                //Get the file stream
                using ( Stream fs = ( Stream )dialog.OpenFile() )  
                {  
                    fs.Write( fileBytes, 0, fileBytes.Length );  
                    fs.Close();  

                    //File successfully saved
                }  
            }  
            catch ( Exception ex )  
            {  
                //inspect ex.Message  
            }  
            */
            //
            if (_skeltanimdata == null)
            {
                System.Windows.Resources.StreamResourceInfo sri = Application.GetResourceStream(new Uri("/MIRIADemo;component/Images/skeltonanim_new.msb", UriKind.Relative));
                _skeltanimdata = serializer.Deserialize(sri.Stream) as List<Dictionary<SkeltonJoint, Point3d>>;
            }
            //
            //
            Thread skeltonanimrecorder = new Thread(new ThreadStart(delegate()
            {
                Kinect.EnableUpdate = false;
                //
                while (_playmode)
                {
                    DateTime starttime = DateTime.Now;
                    for (int x = 0; x < _skeltanimdata.Count; x++)
                    {
                        Kinect.UpdateSkelton(_skeltanimdata[x], true);
                        //
                        TimeSpan timeline = new TimeSpan(DateTime.Now.Ticks - starttime.Ticks);
                        if (timeline.TotalSeconds > 22 && !miriaanimstarted)
                        {
                            miriaanimstarted = true;
                            ButtonMiria.Dispatcher.BeginInvoke(() =>
                            {
                                Animator.FxFadeFar(ButtonMiria, 1.0, 0.25, 0);
                                ButtonMiria.Animate();
                            });
                        }
                        else if (timeline.TotalSeconds > 29 && !miganimstarted)
                        {
                            miganimstarted = true;
                            ButtonMig.Dispatcher.BeginInvoke(() =>
                            {
                                Animator.FxFadeFar(ButtonMig, 1.0, 0.25, 0);
                                ButtonMig.Animate();
                            });
                        }
                        //
                        Thread.Sleep(125);
                    }
                    Thread.Sleep(2000);
                    break;
                }
                //
                Kinect.EnableUpdate = true;
            }));
            skeltonanimrecorder.Start();
        }

        private bool isrecording = false;
        private void KinectRecord_Tapped(object sender, FingerTouchEventArgs e)
        {
            if (isrecording) return;
            isrecording = true;
            //
            List<FrameworkElement> exlist = new List<FrameworkElement>() { KinectDemoButton };
            Animator.FxDecomposePanelClose(ColumnTopRight, 0.5, 0, exlist);
            Animator.AnimateProperty(KinectDemoButton, "GlobalOffsetZ", 0, 430, 0.75, 0.25, null);
            Animator.AnimateProperty(KinectDemoButton, "GlobalOffsetY", 0, -60, 0.75, 0.25, null);
            //
            //
            Thread skeltonanimrecorder = new Thread(new ThreadStart(delegate()
            {
                DateTime dtstart = DateTime.Now;
                if (_skeltanimdata == null)
                {
                    _skeltanimdata = new List<Dictionary<SkeltonJoint, Point3d>>();
                }
                else
                {
                    _skeltanimdata.Clear();
                }
                //
                while (true)
                {
                    TimeSpan elapsedsincestart = new TimeSpan(DateTime.Now.Ticks - dtstart.Ticks);
                    if (elapsedsincestart.TotalSeconds > 10 && elapsedsincestart.TotalSeconds < 40)
                    {
                        KinectRecorderStatus.Dispatcher.BeginInvoke(() =>
                        {
                            KinectRecorderStatus.Text = "RECORDING...  " + ((int)elapsedsincestart.TotalSeconds - 40).ToString();
                        });
                        _skeltanimdata.Add(_currentskelton);
                    }
                    else if (elapsedsincestart.TotalSeconds > 35)
                    {
                        KinectRecorderStatus.Dispatcher.BeginInvoke(() =>
                        {
                            KinectRecorderStatus.Text = "";
                            Animator.FxComposePanelClose(ColumnTopRight, 0.5, 0, exlist);
                            Animator.AnimateProperty(KinectDemoButton, "GlobalOffsetZ", 430, 0, 0.75, 0.25, null);
                            Animator.AnimateProperty(KinectDemoButton, "GlobalOffsetY", -60, 0, 0.75, 0.25, null);
                        });
                        isrecording = false;
                        break;
                    }
                    else
                    {
                        KinectRecorderStatus.Dispatcher.BeginInvoke(() =>
                        {
                            KinectRecorderStatus.Text = "GET READY!  " + (10 - (int)elapsedsincestart.TotalSeconds).ToString();
                        });
                    }
                    Thread.Sleep(100);
                }
            }));
            skeltonanimrecorder.Start();

        }

        private void Border_MouseLeftButtonUp_1(object sender, MouseButtonEventArgs e)
        {
        }

        double currentrotation = 0;
        private void TButton_Tapped(object sender, FingerTouchEventArgs e)
        {
            currentrotation += 90;
            for (int x = 0; x < ColumnTopRight.Children.Count; x++)
            {
                FrameworkElement el = (FrameworkElement)ColumnTopRight.Children[x];
                if (el.Name == "KinectDemoButton")
                {
                    continue;
                }
                Animator.AnimateProperty(el, "RotationZ", currentrotation - 90, currentrotation, 0.25, null);
            }
            if (currentrotation >= 360) currentrotation = 0;
        }

        private void ButtonMiria_Tapped(object sender, FingerTouchEventArgs e)
        {
            HtmlPage.Window.Navigate(new Uri("http://miria.codeplex.com"));
        }

        private void ButtonMig_Tapped(object sender, FingerTouchEventArgs e)
        {
            HtmlPage.Window.Navigate(new Uri("http://sourceforge.net/projects/mono-mig/"));
        }

        private void HalButton_Tapped(object sender, FingerTouchEventArgs e)
        {
            HtmlPage.Window.Navigate(new Uri("http://generoso.info/x10hal"));
        }

        private void FlipoutButton_Tapped(object sender, FingerTouchEventArgs e)
        {
            _animate_pageclose(0.4, 0.0);
            _animate_pageopen(0.4, 3.0);
        }

        private void FlipinButton_Tapped(object sender, FingerTouchEventArgs e)
        {
            _animate_pageclose(0.4, 0.0);
            _animate_pageopenfar(0.4, 1.1);
        }
    }
}
